package com.yox.rpc.transport.netty.server;

import com.yox.rpc.entity.RpcRequest;
import com.yox.rpc.entity.RpcResponse;
import com.yox.rpc.factory.SingletonFactory;
import com.yox.rpc.handler.RequestHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 服务端数据处理器，无需关心序列化问题，只需要处理接收到的 RpcRequest 对象
 */
public class NettyServerHandler extends SimpleChannelInboundHandler<RpcRequest> {
    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    private static RequestHandler requestHandler;

    public NettyServerHandler() {
        requestHandler = SingletonFactory.getInstance(RequestHandler.class);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object event) throws Exception {
        if (event instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) event).state();
            if (state == IdleState.READER_IDLE) {
                logger.info("长时间没有收到心跳包，断开连接...");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, event);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception {
        try{
            if (rpcRequest.getHeartBeat()) {
                logger.info("接收到客户端心跳包...");
                return;
            }
            logger.info("服务端接收到请求：{}", rpcRequest);
            Object response = requestHandler.handle(rpcRequest);
            if(ctx.channel().isActive() && ctx.channel().isWritable()) {
                //注意这里的通道是workGroup中的，而NettyServer中创建的是bossGroup的，不要混淆
                ctx.writeAndFlush(RpcResponse.success(response, rpcRequest.getRequestID()));
            }else {
                logger.error("通道不可写");
            }
        }finally {
         ReferenceCountUtil.release(rpcRequest);
        }

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("处理调用过程时发生了错误");
        cause.printStackTrace();
        ctx.close();
    }
}
